home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC World Komputer 2010 April
/
PCWorld0410.iso
/
pluginy Firefox
/
8352
/
8352.xpi
/
components
/
gfUpdaterService.js
< prev
next >
Wrap
Text File
|
2009-05-24
|
22KB
|
724 lines
/*
* Copyright (C) 2008 by Steve Krulewitz <skrulx@gmail.com>
* Licensed under GPLv2 or later, see file LICENSE in the xpi for details.
*/
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cr = Components.results;
const Cu = Components.utils;
const MINUTE_IN_MS = 60 * 1000;
const DEBUG = false;
const NS_PROFILE_STARTUP_OBSERVER_ID = "profile-after-change";
const NS_PROFILE_SHUTDOWN_OBSERVER_ID = "profile-before-change";
const UPDATE_URL = "http://skrul.com/projects/greasefire/update.php";
const JARFILES = ["include.dat", "exclude.dat", "scripts.db", "info.ini"];
function TRYIGNORE(aFunc) {
try {
aFunc();
}
catch (e) {
Cu.reportError(e);
}
}
function d(s) {
if (DEBUG) {
dump("gfUpdaterService: " + s + "\n");
}
}
function gfUpdaterService() {
d("ctor");
this._gfs = null;
this._prefs = null;
this._isUpdating = false;
this._listeners = [];
this._nextUpdate = null;
this._timer = null;
this._wbp = null;
this._timer;
var obs = Cc["@mozilla.org/observer-service;1"]
.getService(Ci.nsIObserverService);
obs.addObserver(this, NS_PROFILE_STARTUP_OBSERVER_ID, false);
obs.addObserver(this, NS_PROFILE_SHUTDOWN_OBSERVER_ID, false);
}
gfUpdaterService.prototype = {
classDescription: "Greasefire Updater Service",
classID: Components.ID("{7c5b9317-0b18-4390-9a0a-a594d544a99f}"),
contractID: "@skrul.com/greasefire/updater;1"
}
gfUpdaterService.prototype._startup =
function gfUpdaterService__startup()
{
d("startup");
this._gfs = Cc["@skrul.com/greasefire/service;1"]
.getService(Ci.gfIGreasefireService);
this._prefs = Cc["@mozilla.org/preferences-service;1"]
.getService(Components.interfaces.nsIPrefService)
.getBranch("greasefire.");
// If we are overdue for an update at startup, push it a minute in the future
// so we don't slow down startup
if (this.updateIntervalMinutes > 0 && Date.now() > this.nextUpdateDate) {
this._updateNextUpdateDate(1);
}
this._timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
this._timer.initWithCallback(this,
MINUTE_IN_MS,
Ci.nsITimer.TYPE_REPEATING_SLACK);
}
gfUpdaterService.prototype._shutdown =
function gfUpdaterService__shutdown()
{
d("shutdown");
if (this._timer) {
this._timer.cancel();
this._timer = null;
}
}
gfUpdaterService.prototype._updateNextUpdateDate =
function gfUpdaterService__updateNextUpdateDate(aMinutes)
{
var ms = aMinutes * MINUTE_IN_MS;
this._prefs.setCharPref("next_update_date", Date.now() + ms);
}
gfUpdaterService.prototype._processDownload =
function gfUpdaterService__processDownload()
{
var zipReader = Cc["@mozilla.org/libjar/zip-reader;1"]
.createInstance(Ci.nsIZipReader);
var status = Cr.NS_OK;
var message = "OK";
try {
zipReader.open(this._dest);
JARFILES.forEach(function(e) {
zipReader.test(e);
});
// Create a temp dir for unpacking
var em = Cc["@mozilla.org/extensions/manager;1"]
.getService(Ci.nsIExtensionManager);
var installLocation = em.getInstallLocation("greasefire@skrul.com");
var exDir = installLocation.location;
exDir.append("greasefire@skrul.com");
var unpackDir = exDir.clone();
unpackDir.append("indexes.new");
unpackDir.createUnique(Ci.nsIFile.DIRECTORY_TYPE, 0755);
JARFILES.forEach(function(e) {
var f = unpackDir.clone();
f.append(e);
zipReader.extract(e, f);
});
var oldIndexDir = exDir.clone();
oldIndexDir.append("indexes");
var backupDir = exDir.clone();
backupDir.append("indexes.backup");
backupDir.createUnique(Ci.nsIFile.DIRECTORY_TYPE, 0755);
// Stop the greasefire service and move the dirs around
this._gfs.shutdown();
try {
if (oldIndexDir.exists()) {
oldIndexDir.moveTo(backupDir, "");
}
unpackDir.moveTo(null, "indexes");
this._gfs.startup();
}
catch (e) {
// Something went wrong, move things back
Cu.reportError("Error moving indexes " + e.message);
status = Cr.NS_ERROR_FAILURE;
message = "Error moving indexes: " + e.message;
unpackDir.remove(true);
oldIndexDir.moveTo(exDir, "");
this._gfs.startup();
}
// Everything is ok, delete the backup dir
backupDir.remove(true);
}
catch (e) {
Cu.reportError(e);
if (status = Cr.NS_OK) {
status = Cr.NS_ERROR_FAILURE;
message = e.message;
}
}
TRYIGNORE(function() {
zipReader.close();
});
this._updateFinished(status, message);
}
gfUpdaterService.prototype._updateFinished =
function gfUpdaterService__updateFinished(aStatus, aMessage) {
this._isUpdating = false;
if (this._dest) {
var dest = this._dest;
TRYIGNORE(function() {
dest.remove(false);
});
this._dest = null;
}
if (this._wbp) {
this._wbp.progressListener = null;
}
this._wbp = null;
this._notify(function(l) {
l.onUpdateFinished(aStatus, aMessage);
});
}
gfUpdaterService.prototype._notify =
function gfUpdaterService__notify(aFunc)
{
this._listeners.forEach(function(l) {
try {
aFunc(l);
}
catch (e) {
Cu.reportError(e);
}
});
}
// gfIUpdaterService
gfUpdaterService.prototype.startUpdate =
function gfUpdaterService_startUpdate(aForce)
{
if (this._isUpdating) {
return;
}
this._isUpdating = true;
this._notify(function(l) {
l.onUpdateStarted();
});
try {
this._wbp = Cc["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"]
.createInstance(Ci.nsIWebBrowserPersist);
this._wbp.progressListener = this;
// Create a destination file for the download
this._dest = Cc["@mozilla.org/file/directory_service;1"]
.getService(Ci.nsIProperties)
.get("TmpD", Ci.nsIFile);
this._dest.append("greasefire_index_download.jar");
this._dest.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0666);
// Start the download
var ios = Cc["@mozilla.org/network/io-service;1"]
.getService(Ci.nsIIOService);
var uri = ios.newURI(UPDATE_URL, null, null);
var headers = null;
if (this._gfs.indexDate > 0 && !aForce) {
headers = "If-Modified-Since: " +
(new Date(this._gfs.indexDate)).toGMTString() + "\r\n";
}
this._wbp.saveURI(uri, null, null, null, headers, this._dest);
}
catch (e) {
// Something went wrong setting up the download.
Cu.reportError(e);
this._updateFinished(Cr.NS_ERROR_FAILURE, e.message);
}
}
gfUpdaterService.prototype.cancelUpdate =
function gfUpdaterService_cancelUpdate()
{
if (this._isUpdating && this._wbp) {
this._wbp.cancelSave();
}
}
gfUpdaterService.prototype.__defineGetter__("isUpdating",
function gfUpdaterService_get_isUpdating()
{
return this._isUpdating;
});
gfUpdaterService.prototype.__defineGetter__("nextUpdateDate",
function gfUpdaterService_get_nextUpdateDate()
{
try {
return parseInt(this._prefs.getCharPref("next_update_date"));
}
catch(e) {
}
return 0;
});
gfUpdaterService.prototype.__defineGetter__("updateIntervalMinutes",
function gfUpdaterService_get_updateIntervalMinutes()
{
try {
return this._prefs.getIntPref("update_interval_minutes");
}
catch(e) {
}
return 0;
});
gfUpdaterService.prototype.__defineSetter__("updateIntervalMinutes",
function gfUpdaterService_set_updateIntervalMinutes(aMinutes)
{
this._prefs.setIntPref("update_interval_minutes", aMinutes);
this._updateNextUpdateDate(aMinutes);
});
gfUpdaterService.prototype.addListener =
function gfUpdaterService_addListener(aListener)
{
if (this._listeners.indexOf(aListener) >= 0) {
return;
}
this._listeners.push(aListener);
}
gfUpdaterService.prototype.removeListener =
function gfUpdaterService_removeListener(aListener)
{
this._listeners.filter(function(e) {
return aListener != e;
});
}
// nsIWebProgressListener
gfUpdaterService.prototype.onStateChange =
function gfUpdaterService_onStateChange(aWebProgress,
aRequest,
aStateFlags,
aStatus)
{
d("onStateChange");
if (this._isUpdating && aStateFlags & Ci.nsIWebProgressListener.STATE_STOP) {
if (this._wbp.result == Cr.NS_BINDING_ABORTED) {
this._updateFinished(Cr.NS_BINDING_ABORTED, "Cancelled");
return;
}
var responseStatus = null;
try {
responseStatus = aRequest.QueryInterface(Ci.nsIHttpChannel).responseStatus;
}
catch (e) {
}
if (responseStatus == 200) {
this._processDownload();
return;
}
if (responseStatus == 304) {
this._updateFinished(Cr.NS_ERROR_FILE_ALREADY_EXISTS, "Not Modified");
return;
}
this._updateFinished(Cr.NS_ERROR_FAILURE,
"status = 0x" + aStatus.toString(16) + " " +
"http = " + responseStatus);
}
}
gfUpdaterService.prototype.onProgressChange =
function gfUpdaterService_onProgressChange(aWebProgress,
aRequest,
aCurSelfProgress,
aMaxSelfProgress,
aCurTotalProgress,
aMaxTotalProgress)
{
if (this._isUpdating) {
this._notify(function(l) {
l.onDownloadProgress(aCurTotalProgress, aMaxTotalProgress);
});
}
}
gfUpdaterService.prototype.onLocationChange =
function gfUpdaterService_onLocationChange(aWebProgress, aRequest, aLocation)
{
}
gfUpdaterService.prototype.onStatusChange =
function gfUpdaterService_onStatusChange(aWebProgress,
aRequest,
aStatus,
aMessage)
{
}
gfUpdaterService.prototype.onSecurityChange =
function gfUpdaterService_onSecurityChange(aWebProgress, aRequest, aState)
{
}
// nsITimer
gfUpdaterService.prototype.notify =
function gfUpdaterService_notify(aTimer)
{
if (this.updateIntervalMinutes > 0 && Date.now() > this.nextUpdateDate) {
this._updateNextUpdateDate(this.updateIntervalMinutes);
this.startUpdate(false);
}
}
// nsIObserver
gfUpdaterService.prototype.observe =
function gfUpdaterService_observe(aSubject, aTopic, aData)
{
if (aTopic == NS_PROFILE_STARTUP_OBSERVER_ID) {
this._startup();
}
else if (aTopic == NS_PROFILE_SHUTDOWN_OBSERVER_ID) {
this._shutdown();
var obs = Cc["@mozilla.org/observer-service;1"]
.getService(Ci.nsIObserverService);
obs.removeObserver(this, NS_PROFILE_STARTUP_OBSERVER_ID);
obs.removeObserver(this, NS_PROFILE_SHUTDOWN_OBSERVER_ID);
}
}
/*
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 2004
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Alex Fritze <alex@croczilla.com> (original author)
* Nickolay Ponomarev <asqueella@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
/**
* Utilities for JavaScript components loaded by the JS component
* loader.
*
* Import into a JS component using
* 'Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");'
*
* Exposing a JS 'class' as a component using these utility methods consists
* of several steps:
* 0. Import XPCOMUtils, as described above.
* 1. Declare the 'class' (or multiple classes) implementing the component(s):
* function MyComponent() {
* // constructor
* }
* MyComponent.prototype = {
* // properties required for XPCOM registration:
* classDescription: "unique text description",
* classID: Components.ID("{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}"),
* contractID: "@example.com/xxx;1",
*
* // [optional] custom factory (an object implementing nsIFactory). If not
* // provided, the default factory is used, which returns
* // |(new MyComponent()).QueryInterface(iid)| in its createInstance().
* _xpcom_factory: { ... },
*
* // [optional] an array of categories to register this component in.
* _xpcom_categories: [{
* // Each object in the array specifies the parameters to pass to
* // nsICategoryManager.addCategoryEntry(). 'true' is passed for
* // both aPersist and aReplace params.
* category: "some-category",
* // optional, defaults to the object's classDescription
* entry: "entry name",
* // optional, defaults to the object's contractID (unless
* // 'service' is specified)
* value: "...",
* // optional, defaults to false. When set to true, and only if 'value'
* // is not specified, the concatenation of the string "service," and the
* // object's contractID is passed as aValue parameter of addCategoryEntry.
* service: true
* }],
*
* // QueryInterface implementation, e.g. using the generateQI helper
* QueryInterface: XPCOMUtils.generateQI(
* [Components.interfaces.nsIObserver,
* Components.interfaces.nsIMyInterface]),
*
* // ...component implementation...
* };
*
* 2. Create an array of component constructors (like the one
* created in step 1):
* var components = [MyComponent];
*
* 3. Define the NSGetModule entry point:
* function NSGetModule(compMgr, fileSpec) {
* // components is the array created in step 2.
* return XPCOMUtils.generateModule(components);
* }
*/
var XPCOMUtils = {
/**
* Generate a QueryInterface implementation. The returned function must be
* assigned to the 'QueryInterface' property of a JS object. When invoked on
* that object, it checks if the given iid is listed in the |interfaces|
* param, and if it is, returns |this| (the object it was called on).
*/
generateQI: function(interfaces) {
return makeQI([i.name for each(i in interfaces)]);
},
/**
* Generate the NSGetModule function (along with the module definition).
* See the parameters to generateModule.
*/
generateNSGetModule: function(componentsArray, postRegister, preUnregister) {
return function NSGetModule(compMgr, fileSpec) {
return XPCOMUtils.generateModule(componentsArray,
postRegister,
preUnregister);
}
},
/**
* Generate a module implementation.
*
* @param componentsArray Array of component constructors. See the comment
* at the top of this file for details.
* @param postRegister optional post-registration function with
* signature 'postRegister(nsIComponentManager,
* nsIFile, componentsArray)'
* @param preUnregister optional pre-unregistration function with
* signature 'preUnregister(nsIComponentManager,
* nsIFile, componentsArray)'
*/
generateModule: function(componentsArray, postRegister, preUnregister) {
let classes = [];
for each (let component in componentsArray) {
classes.push({
cid: component.prototype.classID,
className: component.prototype.classDescription,
contractID: component.prototype.contractID,
factory: this._getFactory(component),
categories: component.prototype._xpcom_categories
});
}
return { // nsIModule impl.
getClassObject: function(compMgr, cid, iid) {
// We only support nsIFactory queries, not nsIClassInfo
if (!iid.equals(Ci.nsIFactory))
throw Cr.NS_ERROR_NOT_IMPLEMENTED;
for each (let classDesc in classes) {
if (classDesc.cid.equals(cid))
return classDesc.factory;
}
throw Cr.NS_ERROR_FACTORY_NOT_REGISTERED;
},
registerSelf: function(compMgr, fileSpec, location, type) {
var componentCount = 0;
debug("*** registering " + fileSpec.leafName + ": [ ");
compMgr.QueryInterface(Ci.nsIComponentRegistrar);
for each (let classDesc in classes) {
debug((componentCount++ ? ", " : "") + classDesc.className);
compMgr.registerFactoryLocation(classDesc.cid,
classDesc.className,
classDesc.contractID,
fileSpec,
location,
type);
if (classDesc.categories) {
let catMan = XPCOMUtils.categoryManager;
for each (let cat in classDesc.categories) {
let defaultValue = (cat.service ? "service," : "") +
classDesc.contractID;
catMan.addCategoryEntry(cat.category,
cat.entry || classDesc.className,
cat.value || defaultValue,
true, true);
}
}
}
if (postRegister)
postRegister(compMgr, fileSpec, componentsArray);
debug(" ]\n");
},
unregisterSelf: function(compMgr, fileSpec, location) {
var componentCount = 0;
debug("*** unregistering " + fileSpec.leafName + ": [ ");
compMgr.QueryInterface(Ci.nsIComponentRegistrar);
if (preUnregister)
preUnregister(compMgr, fileSpec, componentsArray);
for each (let classDesc in classes) {
debug((componentCount++ ? ", " : "") + classDesc.className);
if (classDesc.categories) {
let catMan = XPCOMUtils.categoryManager;
for each (let cat in classDesc.categories) {
catMan.deleteCategoryEntry(cat.category,
cat.entry || classDesc.className,
true);
}
}
compMgr.unregisterFactoryLocation(classDesc.cid, fileSpec);
}
debug(" ]\n");
},
canUnload: function(compMgr) {
return true;
}
};
},
/**
* Convenience access to category manager
*/
get categoryManager() {
return Components.classes["@mozilla.org/categorymanager;1"]
.getService(Ci.nsICategoryManager);
},
/**
* Returns an nsIFactory for |component|.
*/
_getFactory: function(component) {
var factory = component.prototype._xpcom_factory;
if (!factory) {
factory = {
createInstance: function(outer, iid) {
if (outer)
throw Cr.NS_ERROR_NO_AGGREGATION;
return (new component()).QueryInterface(iid);
}
}
}
return factory;
}
};
/**
* Helper for XPCOMUtils.generateQI to avoid leaks - see bug 381651#c1
*/
function makeQI(interfaceNames) {
return function XPCOMUtils_QueryInterface(iid) {
if (iid.equals(Ci.nsISupports))
return this;
for each(let interfaceName in interfaceNames) {
if (Ci[interfaceName].equals(iid))
return this;
}
throw Cr.NS_ERROR_NO_INTERFACE;
};
}
//@line 420 "/home/steve/dev/mozilla/1.8/mozilla/extensions/greasefire/src/gfUpdaterService.js"
gfUpdaterService.prototype.QueryInterface =
XPCOMUtils.generateQI([Ci.gfIUpdaterService,
Ci.nsIObserver,
Ci.nsIWebProgressListener,
Ci.nsITimerCallback]);
var NSGetModule = XPCOMUtils.generateNSGetModule(
[
gfUpdaterService
],
function(aCompMgr, aFileSpec, aLocation) {
XPCOMUtils.categoryManager.addCategoryEntry(
"app-startup",
gfUpdaterService.prototype.classDescription,
"service," + gfUpdaterService.prototype.contractID,
true,
true);
}
);
function do(o) {
var s = "";
if (typeof(o) == "string") {
s = o;
}
else {
if (o.length) {
}
else {
var a = [];
for (var k in o) {
a.push(k + " => " + o[k]);
}
s = a.join(", ");
}
}
dump("[updater] " + s + "\n");
}